package org.jeecg.board.service.impl;/**
 * @Description
 * @Author LiCY
 * @Date 2023/4/24
 */

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.board.dto.LineBoardBarDTO;
import org.jeecg.board.mapper.LineBoardMapper;
import org.jeecg.board.service.LineBoardService;
import org.jeecg.common.api.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 功能描述：
 *
 * @author: LCY
 * @date: 2023年04月24日 14:01
 */
@Service
@Slf4j
public class LineBoardServiceImpl implements LineBoardService {
    @Autowired
    private LineBoardMapper lineBoardMapper;


    @Autowired
    public RedisTemplate redisTemplate;



    @Override
    public Result<Map<String, Object>> getBoardData(Map<String, Object> param) {
        String line = "";
        if (param.containsKey("line")){
            line = (String) param.get("line");
        }
        String key ="boardData"+"-"+line;
        if (redisTemplate.hasKey(key)){
            Map<String, Object> data = (Map<String, Object>) redisTemplate.opsForValue().get(key);
            log.info("从redis获取看板数据");
            return Result.OK(data);
        }else{
            HashMap<String, Object> map = new HashMap<>();
            AtomicReference<Double> passRate = new AtomicReference<>((double) 1);
            List<LineBoardBarDTO> stnFtq = lineBoardMapper.getStnFTQ(param);
            List<LineBoardBarDTO> availability = lineBoardMapper.getAvailability(param);
            List<LineBoardBarDTO> performance = lineBoardMapper.getPerformance(param);
            Integer errorNum = lineBoardMapper.getWoErrorNum(param);
            stnFtq.forEach(item -> {
                passRate.updateAndGet(v ->  (v * item.getValue() * 0.01));
            });
            LineBoardBarDTO minAvailability = availability.stream().min(Comparator.comparing(LineBoardBarDTO::getValue)).get();
            LineBoardBarDTO minPerformance = performance.stream().min(Comparator.comparing(LineBoardBarDTO::getValue)).get();

            map.put("ftq", stnFtq);
            map.put("availability", availability);
            map.put("performance", performance);

            String str = String.format("%.2f", passRate.get() * 100);
            //OEE = 45678不合格数/4站开工数 * 瓶颈工序性能稼动率 * 最低的时间稼动率
            Double totalNum = lineBoardMapper.getTotalNum(param);
            Double ngNum = lineBoardMapper.getNGNum(param);
            Double oee = (totalNum-ngNum)/totalNum * minAvailability.getValue()*0.01 * minPerformance.getValue()*0.01;
            String lineOee = String.format("%.2f", oee* 100);
            map.put("passRate", str);
            map.put("lineOee", lineOee);
            map.put("errorNum", errorNum);
            log.info("存入看板数据到Redis");
            redisTemplate.opsForValue().set(key, map, 120, TimeUnit.SECONDS);
            return Result.OK(map);
        }
    }

    @Override
    public Result<Map<String, Object>> getQualityBoardData(Map<String, Object> param) {
        String line = "";
        if (param.containsKey("line")){
            line = (String) param.get("line");
        }
        String key = "QisBoardData"+"-"+line;
        if (redisTemplate.hasKey(key)) {
            Map<String, Object> data = (Map<String, Object>) redisTemplate.opsForValue().get(key);
            if (data != null) {
                Date now = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                String formattedDate = sdf.format(now);
                data.put("time", formattedDate);
            }
            log.info("从redis获取看板数据");
            return Result.OK(data);
        } else {
            HashMap<String, Object> map = new HashMap<>();
            List<String> product = new ArrayList<>(Arrays.asList("OP80", "OP90"));
            List<String> semi1 = new ArrayList<>(Arrays.asList("OP30"));
            List<String> semi = new ArrayList<>(Arrays.asList("OP30", "OP40", "OP50", "OP60", "OP70"));
            AtomicReference<Double> passRate = new AtomicReference<>((double) 1);
            List<LineBoardBarDTO> stnFtq = lineBoardMapper.getStnFTQ(param);
            //计算成品合格率
            Integer productTotalNum = lineBoardMapper.getOpTotalNum(param, product);
            int productError = lineBoardMapper.getOpErrorNum(param, product).size();
            Integer semiTotalNum = lineBoardMapper.getOpTotalNum(param, semi1);
            int semiError = lineBoardMapper.getOpErrorNum(param, semi).size();

            map.put("ftq", stnFtq);
            map.put("productTotalNum", productTotalNum);
            map.put("productError", productError);
            map.put("semiTotalNum", semiTotalNum);
            map.put("semiError", semiError);
            String productPassRate = String.format("%.2f", (productTotalNum-productError)/(double)productTotalNum * 100);
            String semiPassRate = String.format("%.2f", (semiTotalNum-semiError)/(double)semiTotalNum * 100);
            map.put("productPassRate", productPassRate);
            map.put("semiPassRate", semiPassRate);
            //OEE = 45678不合格数/4站开工数 * 瓶颈工序性能稼动率 * 最低的时间稼动率
            map.put("errorNum", 0);
            Date now = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm");
            String formattedDate = sdf.format(now);
            map.put("time", formattedDate);
            log.info("存入看板数据到Redis");
            redisTemplate.opsForValue().set(key, map, 120, TimeUnit.SECONDS);
            return Result.OK(map);
        }
    }

    @Override
    public Result<Map<String, Object>> getBoardData2(Map<String, Object> param) {
        String line = "";
        if (param.containsKey("line")){
            line = (String) param.get("line");
        }
        String key = "lineBoardData"+"-"+line;
        //1 计算小时产量
        HashMap<String, Object> map = new HashMap<>();
        List<String> timeList = lineBoardMapper.getTimeList(param);
        List<Integer> planNum = lineBoardMapper.getPlanNum(param);
        List<Integer> actualNum = lineBoardMapper.getActualNum(param);
        Double todayDowntime = lineBoardMapper.getTodayDowntime(param);
        Double availability =  lineBoardMapper.getLineAvailability(param);
        Double performance =  lineBoardMapper.getLinePerformance(param);
        Double todayQualifiedNum = lineBoardMapper.getTodayQualifiedNum(param);
        Double todayUnqualifiedNum = lineBoardMapper.getTodayUnqualifiedNum(param);
        List<LineBoardBarDTO> unqualifiedCause = lineBoardMapper.getUnqualifiedCause(param);
        List<LineBoardBarDTO> alarmDuration = lineBoardMapper.getAlarmDuration(param);
        List<LineBoardBarDTO> alarmNum = lineBoardMapper.getAlarmNum(param);
        map.put("timeList",timeList);
        map.put("planNum",planNum);
        map.put("actualNum",actualNum);
        map.put("unqualifiedCause",unqualifiedCause);
        map.put("alarmDuration",alarmDuration);
        map.put("alarmNum",alarmNum);
        DecimalFormat decimalFormat = new DecimalFormat("#0.00");
        // 将要格式化的数字传入 format() 方法进行处理
        double tcr = availability/(todayDowntime*8);
        double pr = performance/(todayDowntime/30);
        double ftq = todayQualifiedNum / (todayQualifiedNum + todayUnqualifiedNum);
        double oee = tcr*pr*ftq;
        map.put("availability",decimalFormat.format(tcr*100));
        map.put("performance",decimalFormat.format(pr*100));
        map.put("ftq",decimalFormat.format(ftq*100));
        map.put("oee",decimalFormat.format(oee*100));
        return Result.OK(map);
    }

    /**
     * 获取产线看板生产数据 （工单进度，小时累计产量，小时产量）
     * @param param
     * @return Result<Map<String, Object>>
     */
    @Override
    public Result<Map<String, Object>> getLineBoardProductionData(Map<String, Object> param) {
        DynamicDataSourceContextHolder.clear();
        DynamicDataSourceContextHolder.push("history");
        String line = "";
        if (param.containsKey("line")){
            line = (String) param.get("line");
        }
        String key = "lineBoardData"+"-"+line;
        Integer woIdNum = lineBoardMapper.getWoidNum(param);
        HashMap<String, Object> map = new HashMap<>();
        map.put("woIdNum",woIdNum);
        Integer beat = lineBoardMapper.getProductBeat(param);
        param.put("beat",beat);
        List<String> classPlanTotalNum = lineBoardMapper.getClassPlanTotalNum(param);
        map.put("classPlanTotalNum",classPlanTotalNum);
        List<String> classAlarmTotalNum = lineBoardMapper.getClassAlarmTotalNum(param);
        map.put("classAlarmTotalNum",classAlarmTotalNum);
        List<String> classTimeList = lineBoardMapper.getClassTimeList(param);
        map.put("classTimeList",classTimeList);
        DecimalFormat decimalFormat = new DecimalFormat("#0.00");
        Double availability =  lineBoardMapper.getLineAvailability(param);
        Double performance =  lineBoardMapper.getLinePerformance(param);
        Double todayDowntime = lineBoardMapper.getTodayDowntime(param);
        Double todayQualifiedNum = lineBoardMapper.getTodayQualifiedNum(param);
        Double todayUnqualifiedNum = lineBoardMapper.getTodayUnqualifiedNum(param);
        double tcr = availability/(todayDowntime*8);
        double pr = performance/(todayDowntime/27);
        double ftq = todayQualifiedNum / (todayQualifiedNum + todayUnqualifiedNum);
        double oee = tcr*pr*ftq;
        map.put("availability",decimalFormat.format(tcr*100));
        map.put("performance",decimalFormat.format(pr*100));
        map.put("ftq",decimalFormat.format(ftq*100));
        map.put("oee",decimalFormat.format(oee*100));
        List<String> lineOPList = lineBoardMapper.getLineOPList(param);
        map.put("lineOPList",lineOPList);
        lineOPList.forEach(item->{
            List<Integer> opPassRate = lineBoardMapper.getOpPassRate(param, item);
            map.put(item,opPassRate);
        });
        List<LineBoardBarDTO> unqualifiedCause = lineBoardMapper.getUnqualifiedCause(param);
        List<LineBoardBarDTO> alarmDuration = lineBoardMapper.getAlarmDuration(param);
        List<LineBoardBarDTO> alarmNum = lineBoardMapper.getAlarmNum(param);
        getPercent(alarmDuration);
        getPercent(unqualifiedCause);
        getPercent(alarmNum);
        map.put("unqualifiedCause",unqualifiedCause);
        map.put("alarmDuration",alarmDuration);
        map.put("alarmNum",alarmNum);
        List<Integer> planNum = lineBoardMapper.getPlanNum(param);
        List<Integer> actualNum = lineBoardMapper.getActualNum(param);
        map.put("planNum",planNum);
        map.put("actualNum",actualNum);
        List<Double> lineOPRunList = lineBoardMapper.getLineOPRunList(param);
        String start = param.get("start").toString();
        DateFormat fmt =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try{
            Date date = fmt.parse(start);
            Date now = new Date();
            long l = (now.getTime() - date.getTime())/(1000*60);
            List<Double> doubles = new ArrayList<>();
            DecimalFormat df = new DecimalFormat("#.00");
            lineOPRunList.forEach(item->{
                double v = l - item;
                String formattedNumber = df.format(v);
                double result = Double.parseDouble(formattedNumber);
                doubles.add(result);
            });
            map.put("lineOPStopList",doubles);
        }catch (Exception e){
            e.printStackTrace();
        }

        //List<String> lineOPStopList = lineBoardMapper.getLineOPStopList(param);
        map.put("lineOPRunList",lineOPRunList);
        log.info("存入新看板数据到Redis");
        redisTemplate.opsForValue().set(key, map, 360, TimeUnit.SECONDS);
        return Result.OK(map);
    }
    private void getPercent(List<LineBoardBarDTO> list){
        AtomicReference<Double> num = new AtomicReference<>(0.0);
        DecimalFormat decimalFormat = new DecimalFormat("#0.00");
        list.forEach(item->{
            num.updateAndGet(v -> new Double((double) (v + item.getValue())));
        });
        list.forEach(item->{
            item.setPercent(decimalFormat.format(item.getValue()/num.get()*100));
        });
    }
    @Override
    public Result<Map<String, Object>> getLineBoardData(Map<String, Object> param) {
        String line = "";
        if (param.containsKey("line")){
            line = (String) param.get("line");
        }
        String key = "lineBoardData"+"-"+line;
        Map<String, Object> data = (Map<String, Object>) redisTemplate.opsForValue().get(key);
        log.info("从redis获取看板数据");
        return Result.OK(data);
    }

}
